#include <basic_types.h>
#include <mediatypes.h>

#include <sys_config.h>
#ifndef DISABLE_OTA

#include <bus/dog/dog.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <api/libc/alloc.h>

#include <api/libdbc/lib_dbc.h>
#include <bus/dog/dog.h>
#include <api/libtsi/sec_pat.h>
#include <api/libtsi/sec_pmt.h>
#include <api/libtsi/p_search.h>
#include <api/libnim/lib_nim.h>

#include <hld/hld_dev.h>
#include <hld/sto/sto.h>
#include <hld/dmx/dmx.h>
#include <hld/decv/vdec_driver.h>
#include <hld/nim/nim_dev.h>


#include <api/libtsi/si_descriptor.h>

#include <api/libota/lib_ota.h>

#if (defined HDCP_IN_FLASH)
#include <api/libchunk/chunk.h>
#endif

#define OTA_PRINTF  PRINTF

#ifdef CA_NO_CRC_ENABLE
#define NCRC_VALUE	0x40232425	// "@#$%"
#else
#define NCRC_VALUE	0x4E435243	// "NCRC"
#endif

#ifdef _CAS9_CA_ENABLE_ // define another meaningless CRC value for security
	#define CAS9_NCRC_VALUE		0x40232425	// "@#$%"
#else
	#define CAS9_NCRC_VALUE 	NCRC_VALUE
#endif

/*
static char STB_ID[24] = "110800103011000000000001";

11 	: reserved
09 	: last byte of OUI
001	: set number
03	: box type 
01	: HW version
1	: serial type
000000000001
	: serial number
*/


#if 0//(SYS_PROJECT == PROJECT_HDTV)
UINT16	g_model  	= (SYS_HW_MODEL&0xffff);	//	
UINT32	g_oui  		;	//	(0x303030|(g_model&0xf)|((g_model&0xf0)<<4)|((g_model&0xf00)<<8))
UINT16	g_stb_type	  ;	//	stbid_get_field_stb_type()
UINT16	g_hw_version ; 	//	stbid_get_field_hw_ver()
UINT16	g_sw_model  	;
UINT16	g_sw_version ;//= SYS_SW_VERSION&0xffff;
UINT8	g_version_control =0; //do if(version >= last_version)

UINT8	g_download_type;//  =	0x02;
UINT8*	g_set_number;  	//	stbid_get_field_group()
UINT8*	g_serial_number;//  	stbid_get_field_number()

#else
UINT32	g_oui  		=		(SYS_OUI&0xffffff);
UINT16	g_model  	=		(SYS_HW_MODEL&0xffff);
UINT16	g_hw_version  =		(SYS_HW_VERSION&0xffff);
UINT16	g_sw_model  	=		(SYS_SW_MODEL&0xffff);
UINT16	g_sw_version ;//= SYS_SW_VERSION&0xffff;
UINT8	g_download_type;//  =	0x02;
UINT8*	g_set_number;  	//	stbid_get_field_group()
UINT8*	g_serial_number;//  	stbid_get_field_number()
#endif

static OSAL_ID g_ota_tsk_id;
static OSAL_ID g_ota_mbf_id = OSAL_INVALID_ID;
OSAL_ID  g_ota_flg_id = OSAL_INVALID_ID;

static UINT8* g_ota_ram1_addr;// = (UINT8*)__MM_TTX_PB_START_ADDR;
static UINT32 g_ota_ram1_len;

static UINT32 g_ota_size;

static UINT8* g_ota_ram2_addr;// = (UINT8*)__MM_DVW_START_ADDR;
static UINT32 g_ota_ram2_len;
static INT32 g_ota_size_2;

static UINT8* g_ota_swap_addr;// = (UINT8*)__MM_SUB_PB_START_ADDR;


struct DCGroupInfo g_dc_group;
#define DC_MODULE_MAX 	4
struct DCModuleInfo g_dc_module[DC_MODULE_MAX];
UINT8 	g_dc_module_num;
UINT16	g_dc_blocksize;



#define g_ota_section_buf_len 5000 

static UINT8 g_ota_section_buf[g_ota_section_buf_len];


static struct service_info g_service_info;
static struct dl_info g_dl_info;
static UINT32 g_lnb_frequency;

static INT32 received_section_num;
static INT32 total_block_num;
static t_progress_disp download_progress_disp;


#ifdef OTA_CONTROL_FLOW_ENHANCE
INT32 ota_send_cmd(struct ota_cmd* cmd,UINT32 tmout);
#endif



INT32 parse_dsmcc_sec(UINT8 *buffer, INT32 buffer_length, void *param)
{
	BOOL ret;
	
	UINT8 byte_hi,byte_lo;
	UINT8 table_id,section_num,last_section_num;
	UINT16 section_len,table_id_extension;
	UINT16 new_sw_version;

	struct section_param *sec_param = (struct section_param *)param;
	

	table_id = *buffer++;
	byte_hi = *buffer++;
	byte_lo = *buffer++;
	section_len = ((byte_hi&0x0f)<<8) + byte_lo;
	byte_hi = *buffer++;
	byte_lo = *buffer++;
	table_id_extension = (byte_hi<<8) + byte_lo;	
	byte_lo = *buffer++;
	section_num = *buffer++;
	last_section_num = *buffer++;

	switch(sec_param->section_type)
	{
		case 0x00: /*------------------STEP_DSI---------------------------*/	

			if(table_id_extension!=0x0000 && table_id_extension!=0x0001)
				return OTA_FAILURE;
			ret = dsi_message(buffer,
							section_len-9,
							g_oui,	//0xffffff						
							g_model,//8							
							g_hw_version,
							g_sw_model,//8							
							g_sw_version,
							&new_sw_version,
							&g_dc_group);
			if(ret == TRUE)
			{
				g_dl_info.hw_version = (UINT16)g_hw_version;
				g_dl_info.sw_version = new_sw_version;
				g_dl_info.sw_type = 0;
				g_dl_info.sw_size = g_dc_group.group_size;
				return OTA_SUCCESS;
			}
			else
				return OTA_FAILURE;	
		case 0x01: /*------------------STEP_DII---------------------------*/	

			if(table_id_extension!=(g_dc_group.group_id&0xffff))
				return OTA_FAILURE;
			ret = dii_message(buffer,
							section_len-9,
							g_dc_group.group_id,
							g_ota_ram1_addr,
							g_dc_module,
							&g_dc_module_num,
							&g_dc_blocksize);
			if(ret == TRUE)
				return OTA_SUCCESS;
			else
				return OTA_FAILURE;			
			
		case 0x02: /*------------------STEP_DDB---------------------------*/	

			if(table_id_extension!=g_dc_module[sec_param->param8].module_id)
				return OTA_FAILURE;
			ret = ddb_data(buffer,
						section_len-9,
						&g_dc_module[sec_param->param8],
						g_dc_blocksize,
						section_num);
			if(ret == TRUE)
				return OTA_SUCCESS;
			else
				return OTA_FAILURE;
		default:
			return OTA_FAILURE;
	}

}

INT32 si_sections_parsing_start(UINT8 *buff, INT32 buflen, struct table_info *info, section_parser_t section_parser, void *param)
{
	INT32 ret;
	UINT8 break_condition;
	UINT8 section_num = 0;
	UINT8 last_section_num;
	struct dmx_device * dmx_dev;
	if((dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 0)) == NULL)
	{
		OTA_PRINTF("ERROR : get dmx dev failure !");
		return OTA_FAILURE;
	}	

	struct get_section_param sr_request;
	struct restrict sr_restrict;

	MEMSET(&sr_request, 0, sizeof(struct get_section_param));
	MEMSET(&sr_restrict, 0, sizeof(struct restrict));

	sr_request.buff = buff;
	sr_request.buff_len = buflen;
	sr_request.crc_flag = 1;
	sr_request.pid = info->pid;
	sr_request.mask_value = &sr_restrict;	

	sr_request.wai_flg_dly = 30000;

	sr_restrict.mask_len = 7;
	sr_restrict.value_num = 1;
	
	sr_restrict.mask[0] = 0xff;
	sr_restrict.mask[1] = 0x80;
	sr_restrict.mask[2] = 0x00;
	sr_restrict.mask[5] = 0x00;
	sr_restrict.mask[6] = 0xff;
	if(info->attr == DVB_SI_ATTR_SPECIFIC_ID)
	{
		sr_restrict.mask[3] = 0xFF;
		sr_restrict.mask[4] = 0xFF;
		sr_restrict.value[0][3] = (info->specific_id>>8)&0xff;
		sr_restrict.value[0][4] = info->specific_id&0xff;			
	}
	else
	{
		sr_restrict.mask[3] = 0x00;
		sr_restrict.mask[4] = 0x00;
		sr_restrict.value[0][3] = 0x00;
		sr_restrict.value[0][4] = 0x00;
	}
	sr_restrict.value[0][0] = info->table_id;
	sr_restrict.value[0][1] = 0x80;
	sr_restrict.value[0][2] = 0x00;
	sr_restrict.value[0][5] = 0x00;

	section_num =0;
	do{
		sr_restrict.value[0][6] = section_num;

		OTA_PRINTF("Request : section_num = %d\n",section_num);
		if(dmx_req_section(dmx_dev, &sr_request)!= SUCCESS)
		{
			OTA_PRINTF("ERROR : get section failure !");
			return OTA_FAILURE;//ASSERT(0);//return OTA_FAILURE;
		}
		last_section_num = buff[7];
		OTA_PRINTF("Result : section_num = %d,last_section_num = %d \n",section_num,last_section_num);
		ret = section_parser(buff,buflen,param);
		if(ret == OTA_SUCCESS)
			break;	
		section_num++;
		
	}while(section_num<=last_section_num);

	return ret;
}



void ddb_section(struct get_section_param *sr_request)
{
	INT32 modul_idx;
	UINT8* section_buf = sr_request->buff;
	
	UINT16 table_id_extension = (section_buf[3]<<8) +section_buf[4];

	OTA_PRINTF("rcvd :module_id = %x, section_num = %d\n",table_id_extension,section_buf[6]);
	
	for(modul_idx=0;modul_idx<g_dc_module_num;modul_idx++)
	{
		if(g_dc_module[modul_idx].module_id == table_id_extension)
			break;
	}
	if(modul_idx==g_dc_module_num)
		return;
	if((UINT8)(g_dc_module[modul_idx].block_num-1) != section_buf[7])
	{
		OTA_PRINTF("g_dc_module[i].block_num-1 != last_section_num\n");	
		return ;//ASSERT(0);
	}
	
	struct section_param sec_param;
	sec_param.section_type = 2;
	sec_param.param8 = modul_idx;
	if(parse_dsmcc_sec(sr_request->buff,sr_request->buff_len,(void*)(&sec_param)) != OTA_SUCCESS)
		return;
	for(modul_idx=0;modul_idx<g_dc_module_num;modul_idx++)
	{
		if(g_dc_module[modul_idx].module_download_finish != 1)
			break;
	}
	if(modul_idx==g_dc_module_num)
	{
		sr_request->continue_get_sec = 0;
	}
	received_section_num ++;
	OTA_PRINTF("%d%\n",received_section_num*100/total_block_num);
	download_progress_disp(received_section_num*100/total_block_num);	
	return;
}

INT32 si_private_sec_parsing_start(UINT8 section_type,UINT16 pid, section_parser_t section_parser, void *param)
{
	INT32 i;
	struct dmx_device * dmx_dev;
	if((dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 0)) == NULL)
	{
		OTA_PRINTF("ERROR : get dmx dev failure !");
		return OTA_FAILURE;
	}
	struct get_section_param sr_request;
	struct restrict sr_restrict;

	MEMSET(&sr_request, 0, sizeof(struct get_section_param));
	MEMSET(&sr_restrict, 0, sizeof(struct restrict));
	
	sr_request.buff = (UINT8 *)g_ota_section_buf;											
	sr_request.buff_len = g_ota_section_buf_len;
	sr_request.crc_flag = 1;
	sr_request.pid = pid;
	sr_request.mask_value = &sr_restrict;
	sr_request.wai_flg_dly = 2000000;//600000;  //for france low bitrate(10Kbps) ota
	
	if(section_type == 0)
	{
		/* DSI  */
		sr_restrict.mask_len = 7;
		sr_restrict.value_num = 1;
		MEMSET(sr_restrict.mask,0,sr_restrict.mask_len);
		MEMSET(sr_restrict.value[0],0,sr_restrict.mask_len);
		sr_restrict.mask[0] = 0xff;
		sr_restrict.mask[1] = 0x80;		
		sr_restrict.mask[3] = 0xff;
		sr_restrict.mask[4] = 0xfe;	
		sr_restrict.mask[6] = 0xff;
		sr_restrict.value[0][0] = 0x3b;
		sr_restrict.value[0][1] = 0x80;
		sr_restrict.value[0][3] = 0x00;
		sr_restrict.value[0][4] = 0x00;	 //0000 |0001
		sr_restrict.value[0][6] = 0x00;  //section_num = 0		
		
		sr_request.get_sec_cb = NULL;
		sr_request.continue_get_sec = 0;				
	}
	else if(section_type == 1)
	{
		/* DII  */
		sr_restrict.mask_len = 7;
		sr_restrict.value_num = 1;
		MEMSET(sr_restrict.mask,0,sr_restrict.mask_len);
		MEMSET(sr_restrict.value[0],0,sr_restrict.mask_len);	
		sr_restrict.mask[0] = 0xff;
		sr_restrict.mask[1] = 0x80;			
		sr_restrict.mask[3] = 0xff;
		sr_restrict.mask[4] = 0xff;	
		sr_restrict.mask[6] = 0xff;
		sr_restrict.value[0][0] = 0x3b;
		sr_restrict.value[0][1] = 0x80;
		sr_restrict.value[0][3] = ((g_dc_group.group_id)>>8)&0xff;
		sr_restrict.value[0][4] = (g_dc_group.group_id)&0xff;
		sr_restrict.value[0][6] = 0x00;  //section_num = 0	
		
		sr_request.get_sec_cb = NULL;
		sr_request.continue_get_sec = 0;					
	}
	if(section_type == 2)
	{
		/* DDB  */
		if(g_dc_module_num>4)
		{
			sr_restrict.mask_len = 2;
			sr_restrict.value_num = 1;
			MEMSET(sr_restrict.mask,0,sr_restrict.mask_len);
			MEMSET(sr_restrict.value[0],0,sr_restrict.mask_len);	
			sr_restrict.mask[0] = 0xff;
			sr_restrict.mask[1] = 0x80;			
			sr_restrict.value[0][0] = 0x3c;
			sr_restrict.value[0][1] = 0x80;				
		}
		else
		{
			sr_restrict.mask_len = 5;
			sr_restrict.value_num = g_dc_module_num;
			MEMSET(sr_restrict.mask,0,sr_restrict.mask_len);
			sr_restrict.mask[0] = 0xff;
			sr_restrict.mask[1] = 0x80;		
			sr_restrict.mask[3] = 0xff;
			sr_restrict.mask[4] = 0xff;				
			for(i=0;i<g_dc_module_num;i++)
			{
				MEMSET(sr_restrict.value[i],0,sr_restrict.mask_len);					
				sr_restrict.value[i][0] = 0x3c;
				sr_restrict.value[i][1] = 0x80;	
				sr_restrict.value[i][3] = ((g_dc_module[i].module_id)>>8)&0xff;
				sr_restrict.value[i][4] = (g_dc_module[i].module_id)&0xff;					
			}
				
		}

		sr_request.get_sec_cb = ddb_section;
		sr_request.continue_get_sec = 1;
	}

	dmx_io_control(dmx_dev, CB_CHANGE_LEN, 0);
	if(dmx_req_section(dmx_dev, &sr_request)!= SUCCESS)
	{
		OTA_PRINTF("ERROR : get section failure !");
		return OTA_FAILURE;//ASSERT(0);//return OTA_FAILURE;
	}
	dmx_io_control(dmx_dev, CB_RESUME_LEN, 0);
	if(section_parser!=NULL)
		return (section_parser(sr_request.buff,sr_request.buff_len,param));
	return OTA_SUCCESS;

}



INT32 linkage_desc(UINT8 tag, INT32 desc_length, UINT8 *desc, void *param)
{
	UINT8 byte1,byte2,byte3,byte4;
	UINT32 oui;
	UINT8 oui_data_length,selector_length;

	struct service_info *l_service_info = (struct service_info *)param;
	
	UINT8* private_data;
	struct linkage_descriptor *link_desc = (struct linkage_descriptor*)desc;

	l_service_info->transport_stream_id = (link_desc->transport_stream_id[0]<<8)+link_desc->transport_stream_id[1];
	l_service_info->original_network_id = (link_desc->original_network_id[0]<<8)+link_desc->original_network_id[1];
	l_service_info->service_id = (link_desc->service_id[0]<<8)+link_desc->service_id[1];

	//g_service_info.component_tag = desc[13];
	
	OTA_PRINTF("linkage_desc\n");
	private_data =  link_desc->private_data;
	
	switch(link_desc->link_type)
	{
		case 0x04: /*------------------link_type = 0x04---------------------------*/
			OTA_PRINTF("link_type = 0x04\n");
			break;
		case 0x09: /*------------------link_type = 0x09---------------------------*/
			OTA_PRINTF("link_type = 0x09\n");
			oui_data_length = *private_data++;	
			while(oui_data_length)
			{
				
				byte1 = *private_data++;
				byte2 = *private_data++;
				byte3 = *private_data++;
				oui = (byte1<<16)+(byte2<<8)+byte3;	
				selector_length = *private_data++;
				if(oui_data_length<4+selector_length)
				{
					OTA_PRINTF("ERROR : oui_data_length<4+selector_length!\n");
					return OTA_CONTINUE;
				}
				oui_data_length -= (4+selector_length);
				
				OTA_PRINTF("oui = 0x%x\n",oui);
				OTA_PRINTF("g_oui = 0x%x\n",g_oui);
				if(g_oui==oui) //0x303038
				{
					OTA_PRINTF("oui fit!\n");
					l_service_info->private_data = private_data;
					l_service_info->private_len = selector_length;	
					
					return OTA_BREAK;
				}
				private_data += selector_length;	

			}
			return OTA_CONTINUE;
			
		case 0x0a:/*------------------link_type = 0x0a---------------------------*/
			OTA_PRINTF("link_type = 0x0A\n");
			l_service_info->private_data = private_data;
			l_service_info->private_len = 1;
			break;
			
		default :
			OTA_PRINTF("link_type = 0x%x\n",link_desc->link_type);
			break;

	}
	return OTA_BREAK;
}

INT32 stream_identifier_desc(UINT8 tag, INT32 desc_length, UINT8 *desc, void *param)
{
	OTA_PRINTF("stream_identifier_desc\n");
	return OTA_BREAK;
}
INT32 data_broadcast_id_desc(UINT8 tag, INT32 desc_length, UINT8 *desc, void *param)
{
	OTA_PRINTF("data_broadcast_id_desc\n");	
	INT32 oui_data_length,selector_length;
	UINT32 oui;
	
	oui_data_length = desc[2];	
	desc += 3;
	
	while(oui_data_length > 0)
	{		
		oui = (desc[0]<<16)|(desc[1]<<8)|desc[2];	
		
		selector_length = desc[5];
				
		OTA_PRINTF("oui = 0x%x\n",oui);
		if(g_oui==oui)
		{
			OTA_PRINTF("oui fit in databraodcastid desc!\n");
			return OTA_BREAK;
		}
		
		desc += (6+selector_length);	
		oui_data_length -= (6+selector_length);
	}
	
	return OTA_CONTINUE;
}

INT32 check_private_info(UINT8* data, UINT32 len)
{
	UINT8 i;
#if 0//(SYS_PROJECT == PROJECT_HDTV)
	UINT32 hardware_version;
	UINT32 software_version;
	UINT32 serial_num_start;
	UINT32 serial_num_end;
	UINT16 software_type;	
	while(len>=sizeof(struct private_hdtv))
	{
		for(i=0;i<len;i++)
			OTA_PRINTF("0x%x\n",*(data+i));
		struct private_hdtv *hdtv = (struct private_hdtv *)data;
		len -= sizeof(struct private_hdtv);
		data += sizeof(struct private_hdtv);
		/*
		hardware_version = (hdtv->hardware_version[0]<<24)
						+(hdtv->hardware_version[1]<<16)
						+(hdtv->hardware_version[2]<<8)
						+hdtv->hardware_version[3];
		software_version = (hdtv->software_version[0]<<24)
						+(hdtv->software_version[1]<<16)
						+(hdtv->software_version[2]<<8)
						+hdtv->software_version[3];
		serial_num_start = (hdtv->serial_num_start[0]<<24)
						+(hdtv->serial_num_start[1]<<16)
						+(hdtv->serial_num_start[2]<<8)
						+hdtv->serial_num_start[3];
		serial_num_end = (hdtv->serial_num_end[0]<<24)
						+(hdtv->serial_num_end[1]<<16)
						+(hdtv->serial_num_end[2]<<8)
						+hdtv->serial_num_end[3];	
		*/
		hardware_version = ((hdtv->hardware_version[0]-0x30)<<24)
						+((hdtv->hardware_version[1]-0x30)<<16)
						+((hdtv->hardware_version[2]-0x30)<<8)
						+(hdtv->hardware_version[3]-0x30);
		/*
		software_version = ((hdtv->software_version[0]-0x30)<<24)
						+((hdtv->software_version[1]-0x30)<<16)
						+((hdtv->software_version[2]-0x30)<<8)
						+(hdtv->software_version[3]-0x30);
		*/
		software_version = (hdtv->software_version[0]<<24)
						+(hdtv->software_version[1]<<16)
						+(hdtv->software_version[2]<<8)
						+hdtv->software_version[3];

		software_type = 	(hdtv->software_type[0]<<8)
						+hdtv->software_type[1];
		if(hdtv->download_type!=g_download_type)
		{
			OTA_PRINTF("ERROR : download type NOT DC!\n");
			continue;//ASSERT(0);
		}

		//if(hardware_version != (g_stb_type<<16)|g_hw_version)
		if(hardware_version != g_hw_version)
		{
			OTA_PRINTF("ERROR : hw_version NOT compatible!\n");
			OTA_PRINTF("hw_version = 0x%x , g_hw_ver = 0x%x\n",hardware_version,g_hw_version);
			continue;//ASSERT(0);
		}	
		if(software_type==0x0001)//system software
		{
			//to do
		}		
		else
		{
			OTA_PRINTF("ERROR : software_type NOT supported!\n");
			continue;//ASSERT(0);
		}
		if(hdtv->control_code==0x00 && software_version==g_sw_version)
		{
			OTA_PRINTF("ERROR : sw_version same as current!\n");
			continue;//ASSERT(0);
		}		
		else if(software_version <= g_sw_version)
		{
			OTA_PRINTF("ERROR : sw_version Not newer than current!\n");
			continue;//ASSERT(0);
		}		
		if(hdtv->control_code==0x02)//&&((MEMCPY(g_set_number,hdtv->serial_num_start,16)<0)||MEMCPY(g_set_number,hdtv->serial_num_end,16)<0))
		{
			OTA_PRINTF("ERROR : NOT within update set number!\n");
			continue;//ASSERT(0);
		}		
		else if(hdtv->control_code==0x03)//&&((MEMCPY(g_serial_number,hdtv->serial_num_start,16)<0)||MEMCPY(g_serial_number,hdtv->serial_num_end,16)<0))
		{
			OTA_PRINTF("ERROR : NOT within update serial number!\n");
			continue;//ASSERT(0);
		}	
		else if(hdtv->control_code>0x03)
		{
			OTA_PRINTF("ERROR : Unknown control_code !\n");
			continue;//ASSERT(0);
		}			
		g_service_info.component_tag = hdtv->component_tag;
		return OTA_SUCCESS;
	}
	return OTA_FAILURE;
	
#else
	return OTA_SUCCESS;

#endif

}



#ifdef LIB_TSI3_FULL
#include <api/libsi/si_desc_cab_delivery.h>
#include <api/libsi/si_desc_sat_delivery.h>
#include <api/libsi/desc_loop_parser.h>
#include <api/libtsi/si_section.h>

typedef INT32 (*ota_nit_callback)(UINT8 , void*);

struct si_descriptor {
	UINT8 tag;
	UINT8 len;
	UINT8 data[0];
};

static INT32 parse_nit_tp(UINT8 *data, INT32 data_len, ota_nit_callback nit_progress)
{
	INT32 i;
	struct si_descriptor *desc;
	UINT32 polar;
	TP_INFO tp_info;
	INT32 ret = SI_SUCCESS;
	
	for(i=0; i<data_len; i+=sizeof(struct si_descriptor)+desc->len)
	{
		desc = (struct si_descriptor *)(data+i);

#if(SYS_PROJECT_FE == PROJECT_FE_DVBS||SYS_PROJECT_FE == PROJECT_FE_DVBS2)	
		if (desc->tag == SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR)
		{
			struct satellite_delivery_system_descriptor *sat;
			sat = (struct satellite_delivery_system_descriptor *)desc;
			
			polar = sat->polarization;
			tp_info.s_info.polarity = polar<SAT_POL_CIRCLE_LEFT?polar: polar-2;
			tp_info.s_info.frequency = bcd2integer(sat->frequency, 8, 0)/100;
			tp_info.s_info.position = bcd2integer(sat->orbital_position, 4, 0);
			tp_info.s_info.symbol_rate = bcd2integer(sat->symbol_rate, 7, 0)/10;
			if (!sat->west_east_flag)
				tp_info.s_info.position = 3600 - tp_info.s_info.position;
			tp_info.s_info.FEC_inner = sat->FEC_inner;
			if ((ret=nit_progress(0xFF, &tp_info))!=SUCCESS)
				break;
		}
#endif
	}
	return ret;
}

static INT32 parse_nit(UINT8 *data, INT32 data_len, UINT16 filter_stream_id, 
	ota_nit_callback nit_progress)
{
	INT32 dloop_len, i, ts_len;
	struct nit_section *nit;
	struct transport_stream_info *ts_info;
	INT32 ret = SI_SUCCESS;
	
	nit = (struct nit_section *)data;
	dloop_len = SI_MERGE_HL8(nit->network.network_descriptor_length);
	for(i = dloop_len+sizeof(struct nit_section)-4;i<data_len-4;
			i+= ts_len+sizeof(struct transport_stream_info)) 
	{
		ts_info = (struct transport_stream_info *)(data+i);
		ts_len = SI_MERGE_HL8(ts_info->transport_stream_length);
		if ((filter_stream_id == 0xFFFF)  
			|| (SI_MERGE_UINT16(ts_info->transport_stream_id) == filter_stream_id))
		{
			if ((ret = parse_nit_tp(ts_info->descriptor, ts_len, nit_progress)) != SI_SUCCESS)
				break;
		}
	}
		
	return ret;
}

INT32 parse_nit_bat_2(UINT8 *buffer, INT32 buffer_length, void *param)
{
	INT32 ret;
	struct nit_bat_ts_proc* ts_param = (struct nit_bat_ts_proc*)param;

	OTA_PRINTF("ts_id = %d\n",ts_param->ts_id);
	ret = parse_nit(buffer,buffer_length,ts_param->ts_id,ts_param->proc);

	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : dvb_parse_nit failed!\n");
		return OTA_FAILURE;
	}	
	return OTA_SUCCESS;
}

#else
INT32 parse_nit_bat_2(UINT8 *buffer, INT32 buffer_length, void *param)
{
	INT32 ret;
	struct nit_bat_ts_proc* ts_param = (struct nit_bat_ts_proc*)param;

	OTA_PRINTF("ts_id = %d\n",ts_param->ts_id);
#ifndef PORTING_ATSC  //atsc_pvr
	ret = dvb_parse_nit(buffer,buffer_length,ts_param->ts_id,ts_param->proc);
#endif
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : dvb_parse_nit failed!\n");
		return OTA_FAILURE;
	}	
	return OTA_SUCCESS;
}

#endif
	

INT32 parse_nit_bat(UINT8 *buffer, INT32 buffer_length, void *param)
{
	INT32 ret ;

	UINT8* desc_ptr;
	INT32 desc_len; 
	UINT8 mask_value[7];//from desc content
	UINT8 good_value[7];//from desc content

	struct descriptor_info info;
	MEMSET(mask_value,0,7);
	MEMSET(good_value,0,7);

	info.mask = mask_value;
	info.value = good_value;

	switch((UINT32)param)
	{
		case CHECK_STEP1: /*------------------CHECK_STEP1---------------------------*/			

		mask_value[6] = 0xff;
		good_value[6] = 0x04;//

		info.mask_len = 7;
		info.descriptor_tag = 0x4A;
		info.on_descriptor = linkage_desc;
		info.priv = (void*)(&g_service_info);

		desc_ptr = buffer+10;
		desc_len = (INT32)(((buffer[8]&0x0f)<<8)+buffer[9]);
		if(desc_len == 0)
		{
			OTA_PRINTF("ERROR : Section does not contain desc.\n");
			return OTA_FAILURE;
		}
		//ret = si_filter_descriptor(desc_ptr, desc_len, &f_params);
#ifdef LIB_TSI3_FULL
		ret = si_descriptor_parser(desc_ptr, desc_len, &info, 1);
#else
		ret = si_parse_content(desc_ptr, desc_len, &info, 1);
#endif
		if(ret != OTA_BREAK)
		{
			OTA_PRINTF("ERROR : No  ota service exist!\n");
			return OTA_FAILURE;
		}	
		/*
		ret = dvb_parse_nit(buffer,buffer_length,g_service_info.transport_stream_id,change_transponder);

		if(ret != OTA_SUCCESS)
		{
			OTA_PRINTF("ERROR : No  ota service exist!\n");
			return OTA_FAILURE;
		}
		*/
		
		break;
		
		case CHECK_STEP2:/*------------------CHECK_STEP2---------------------------*/				

		mask_value[6] = 0xff;
		good_value[6] = 0x0A;//

		info.descriptor_tag = 0x4A;
		info.mask_len = 7;
		info.on_descriptor = linkage_desc;
		info.priv = (void*)(&g_service_info);

		desc_ptr = buffer+10;
		desc_len = (INT32)(((buffer[8]&0x0f)<<8)+buffer[9]);
		if(desc_len == 0)
		{
			OTA_PRINTF("ERROR : Section does not contain desc.\n");
			return OTA_FAILURE;
		}		
		//ret = si_filter_descriptor(desc_ptr, desc_len, &f_params);
#ifdef LIB_TSI3_FULL
		ret = si_descriptor_parser(desc_ptr, desc_len, &info, 1);
#else
		ret = si_parse_content(desc_ptr, desc_len, &info, 1);
#endif
		if(ret != OTA_BREAK)
		{
			OTA_PRINTF("ERROR : si_parse_content failed!\n");
			return OTA_FAILURE;
		}		
		OTA_PRINTF("OTA : step 2:  si_parse_content DONE!\n");
		/*
		ret = dvb_parse_nit(buffer,buffer_length,g_service_info.transport_stream_id,change_transponder);

		if(ret != OTA_SUCCESS)
		{
			OTA_PRINTF("ERROR : dvb_parse_nit failed!\n");
			return OTA_FAILURE;
		}	
		OTA_PRINTF("OTA : step 2:  dvb_parse_nit DONE!\n");
		*/
		break;
		
		case CHECK_STEP3:/*------------------CHECK_STEP3---------------------------*/			

		mask_value[6] = 0xff;
		good_value[6] = 0x09;//

		info.descriptor_tag = 0x4A;
		info.mask_len = 7;
		info.on_descriptor = linkage_desc;
		info.priv = (void*)(&g_service_info);

		desc_ptr = buffer+10;
		desc_len = (INT32)(((buffer[8]&0x0f)<<8)+buffer[9]);
		if(desc_len == 0)
		{
			OTA_PRINTF("ERROR : Section does not contain desc.\n");
			return OTA_FAILURE;
		}	
#ifdef LIB_TSI3_FULL
		ret = si_descriptor_parser(desc_ptr, desc_len, &info, 1);
#else
		ret = si_parse_content(desc_ptr, desc_len, &info, 1);
#endif

		if(ret != OTA_BREAK)
		{//No desc fit (fit : success&break)
			OTA_PRINTF("ERROR : si_parse_content failed!\n");
			return OTA_FAILURE;
		}		
		OTA_PRINTF("OTA : step 3:  si_parse_content DONE!\n");

#if 1
	/* Move to here -> check_private_info */	
		ret = check_private_info(g_service_info.private_data,g_service_info.private_len);
		if(ret != OTA_SUCCESS)
		{
			OTA_PRINTF("ERROR : Service Not fit !\n");
			return OTA_FAILURE;
		}	
		OTA_PRINTF("OTA : step 6:  check_private_info DONE!\n");
#else
		g_service_info.component_tag = 0x01;
#endif

		/*
		ret = dvb_parse_nit(buffer,buffer_length,g_service_info.transport_stream_id,change_transponder);

		if((ret & OTA_SUCCESS)==0)
		{
			OTA_PRINTF("ERROR : dvb_parse_nit failed!\n");
			return OTA_FAILURE;
		}	
		OTA_PRINTF("OTA : step 3:  dvb_parse_nit DONE!\n");
		*/
		
		break;		
		
		default :/*------------------INVALID---------------------------*/			
			OTA_PRINTF("ERROR : step error!\n");
			return OTA_FAILURE;
	}
	return OTA_SUCCESS;

}

#if (((SYS_PROJECT_FE != PROJECT_FE_DVBT) && (SYS_PROJECT_FE != PROJECT_FE_ISDBT)) \
	|| (((SYS_PROJECT_FE == PROJECT_FE_DVBT) || (SYS_PROJECT_FE == PROJECT_FE_ISDBT)) &&(defined(SURPORT_NIT_SEARCH))))
INT32 change_transponder(UINT8 reserved, void* node) 
{
	UINT8 lock;
	UINT8 unlock_timeout=0;
	TP_INFO *tp_info = (TP_INFO *)node;
	UINT32 frequency;

	//for remove the lib_nim.c
	struct NIM_Channel_Change cc_param;
	struct nim_device *dev_nim;
	dev_nim = (struct nim_device *)dev_get_by_id(HLD_DEV_TYPE_NIM, 0);
#if(SYS_PROJECT_FE == PROJECT_FE_DVBS||SYS_PROJECT_FE == PROJECT_FE_DVBS2)
	frequency = tp_info->s_info.frequency - g_lnb_frequency;
	cc_param.freq = frequency;
	cc_param.sym  = tp_info->s_info.symbol_rate;
	cc_param.modulation = 0;
	nim_ioctl_ext(dev_nim, NIM_DRIVER_CHANNEL_CHANGE, (void *)( &cc_param));
#elif (SYS_PROJECT_FE == PROJECT_FE_DVBC)
	cc_param.freq = tp_info->c_info.frequency;
	cc_param.sym  = tp_info->s_info.symbol_rate;
	cc_param.modulation = tp_info->c_info.modulation;
	nim_ioctl_ext(dev_nim, NIM_DRIVER_CHANNEL_CHANGE, (void *)( &cc_param));
#elif (SYS_PROJECT_FE == PROJECT_FE_DVBT) || (SYS_PROJECT_FE == PROJECT_FE_ISDBT)
	api_nim_channel_change(tp_info->c_info.frequency, tp_info->c_info.symbol_rate, tp_info->c_info.modulation);
#endif

	nim_get_lock(dev_nim, &lock);
	while(lock==0)
	{				
		if(unlock_timeout++>100)
		{			
			OTA_PRINTF("ERROR : channel change get lock time out!\n");
			return OTA_FAILURE;
		}
		osal_task_sleep(50);
		nim_get_lock(dev_nim, &lock);
	}	
	OTA_PRINTF("frequency = %d!\n",tp_info->c_info.frequency);
	OTA_PRINTF("symbol_rate = %d!\n",tp_info->c_info.symbol_rate);
	OTA_PRINTF("modulation = %d!\n",tp_info->c_info.modulation);
	OTA_PRINTF("change_transponder SUCCESS!\n");
	return OTA_SUCCESS;	

}
#endif


INT32 parse_pat(UINT8 *buffer, INT32 buffer_length, void *param)
{
	UINT8 *pg_info = NULL;
	UINT16 prog_number = 0;
	struct service_info *info = (struct service_info *)param;
	UINT16 section_len = ((buffer[1]<<8)+buffer[2]) & 0xfff;

	info->pmt_pid = 0xffff;
	pg_info = buffer + 8;
	section_len -= 9;
	while(section_len > 0)
	{
		prog_number = (pg_info[0]<<8)|pg_info[1];
		if(prog_number==info->service_id)
		{
			info->pmt_pid = ((pg_info[2]&0x1F)<<8)|pg_info[3];
			OTA_PRINTF("pmt_pid = %d \n",info->pmt_pid);
			break;
		}
		pg_info += 4;
		section_len -= 4;
	}
	if(info->pmt_pid==0xffff) 
	{	
		OTA_PRINTF("ERROR : No needed service id exist in pat!\n");
		return OTA_FAILURE;
	}
	return OTA_SUCCESS;
}

INT32 parse_pmt(UINT8 *buffer, INT32 buffer_length, void *param)
{
	UINT8 i;
	INT32 ret;
	INT16 es_info_len;

	UINT16 es_pid;

	struct service_info *ser_info = (struct service_info *)param;
	ser_info->ota_pid = 0xffff;

	UINT8 mask_value[2];//from desc content
	UINT8 good_value[2];//from desc content

	struct descriptor_info desc_info;
	MEMSET(mask_value,0,2);
	MEMSET(good_value,0,2);
	
	desc_info.mask = mask_value;
	desc_info.value = good_value;	

	
	INT16 section_len = ((buffer[1]<<8)+buffer[2]) & 0xfff;
	INT16 p_info_len = ((buffer[10]<<8)+buffer[11]) & 0xfff;

	buffer += (12+p_info_len);
	buffer_length = section_len - 9 - p_info_len - 4;
	while(buffer_length)
	{
		es_pid = ((buffer[1]<<8)+buffer[2]) & 0x1fff;
		es_info_len = ((buffer[3]<<8)+buffer[4]) & 0xfff;
		if(buffer_length<(5+es_info_len))
		{
			break;
		}
	#if 0//(SYS_PROJECT == PROJECT_HDTV)	
		mask_value[0] = 0xff;
		good_value[0] = ser_info->component_tag;//
		OTA_PRINTF("com_tag = %d \n",ser_info->component_tag);

		desc_info.mask_len = 1;
		desc_info.descriptor_tag = 0x52;
		desc_info.on_descriptor = stream_identifier_desc;
		desc_info.priv = 0;	
	#else	
		mask_value[0] = 0xff;
		mask_value[1] = 0xff;
		good_value[0] = 0x00;//
		good_value[1] = 0x0A;//

		desc_info.mask_len = 2;
		desc_info.descriptor_tag = 0x66;
		desc_info.on_descriptor = data_broadcast_id_desc;
		desc_info.priv = 0;				
	#endif
#ifdef LIB_TSI3_FULL
		ret = si_descriptor_parser(buffer+5, es_info_len, &desc_info, 1);
#else
		ret = si_parse_content(buffer+5, es_info_len, &desc_info, 1);
#endif
		if(ret == OTA_BREAK)
		{//No desc fit (fit : success&break)
			ser_info->ota_pid = es_pid;
			OTA_PRINTF("OTA : pmt:  si_parse_content DONE!\n");					
			return OTA_SUCCESS;
		}		
		buffer += (5+es_info_len);
		buffer_length -= (5+es_info_len);
	}
	OTA_PRINTF("ERROR : pmt si_parse_content failed!\n");
		
	return OTA_FAILURE;
	
}

BOOL ota_cmd_check_service(UINT16* pid)
{
	INT32 ret;
	UINT32 step;
	struct section_param sec_param;
	struct table_info req_table;
	struct nit_bat_ts_proc ts_param;


#if (SYS_PROJECT_FE == PROJECT_FE_DVBC) /* no step 1&2 */ /******PROJECT_HDTV****************/

#if 0//(SYS_PROJECT == PROJECT_HDTV)
	UINT8 *code;
	
	code  =stbid_get_field_manufactory();
	g_oui  = 0x300000 + (code[0]<<8) +code[1];
	code=stbid_get_field_stb_type();
	g_stb_type=((code[0]-0x30)<<8) +(code[1]-0x30);
	code=stbid_get_field_hw_ver();
	g_hw_version=((code[0]-0x30)<<8) +(code[1]-0x30);

	g_download_type  =	0x01;//0x02;
	g_set_number=stbid_get_field_group();
	g_serial_number=stbid_get_field_number();
#endif

/* step 3 : get linkage_desc 0x09 */
	step = CHECK_STEP3;
	
	req_table.pid = NIT_PID;
	req_table.table_id = 0x40;
	req_table.attr = 0;	
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_nit_bat,
								(void*)step);
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 3.1 error!\n");
		return FALSE;
	}	
	OTA_PRINTF("OTA : step 3.1 DONE!\n");

	OTA_PRINTF("transport_stream_id = 0x%x\n",g_service_info.transport_stream_id);
	OTA_PRINTF("original_network_id = 0x%xn",g_service_info.original_network_id);
	OTA_PRINTF("service_id = 0x%x\n",g_service_info.service_id);
	OTA_PRINTF("component_tag = 0x%x\n",g_service_info.component_tag);

	
	req_table.pid = NIT_PID;
	req_table.table_id = 0x40;
	req_table.attr = 0;		
	ts_param.ts_id = g_service_info.transport_stream_id;
	ts_param.proc = change_transponder;
		
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_nit_bat_2,
								(void*)(&ts_param));
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 3.2 error!\n");
		return FALSE;
	}		
	
	OTA_PRINTF("OTA : step 3.2 DONE!\n");

#elif (SYS_PROJECT_FE == PROJECT_FE_DVBT) || (SYS_PROJECT_FE == PROJECT_FE_ISDBT)// SSUS standard
#ifdef SURPORT_NIT_SEARCH
/* step 3 : get linkage_desc 0x09 */
	step = CHECK_STEP3;
	
	req_table.pid = NIT_PID;
	req_table.table_id = 0x40;
	req_table.attr = 0;
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_nit_bat,
								(void*)step);
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 3 error!\n");
		return FALSE;
	}	
	OTA_PRINTF("OTA : step 3.1 DONE!\n");

	
	req_table.pid = NIT_PID;
	req_table.table_id = 0x40;
	req_table.attr = 0;		
	ts_param.ts_id = g_service_info.transport_stream_id;
	ts_param.proc = change_transponder;

       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_nit_bat_2,
								(void*)(&ts_param));
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 3 error!\n");
		return FALSE;
	}	

	OTA_PRINTF("OTA : step 3.2 DONE!\n");
#endif	

#elif (SYS_PROJECT_FE == PROJECT_FE_DVBS||SYS_PROJECT_FE == PROJECT_FE_DVBS2) //STEP 1,2,3 is defined by ASTRA
/* step 1 : get linkage_desc 0x04 */

	step = CHECK_STEP1;	

	req_table.pid = NIT_PID;
	req_table.table_id = 0x40;
	req_table.attr = 0;
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_nit_bat,
								(void*)step);
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : No  ota service exist!\n");
		return FALSE;
	}	
	OTA_PRINTF("OTA : step 1.1 DONE!\n");

	req_table.pid = NIT_PID;
	req_table.table_id = 0x40;
	req_table.attr = 0;	
	ts_param.ts_id = g_service_info.transport_stream_id;
	ts_param.proc = change_transponder;	
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_nit_bat_2,
								(void*)(&ts_param));
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 1 error!\n");
		return FALSE;
	}			
	OTA_PRINTF("OTA : step 1.2 DONE!\n");

/* step 2 : get linkage_desc 0x0A */	
	step = CHECK_STEP2;
	
	req_table.pid = NIT_PID;
	req_table.table_id = 0x40;
	req_table.attr = 0;	
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_nit_bat,
								(void*)step);
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 2 error!\n");
		return FALSE;
	}	
	OTA_PRINTF("OTA : step 2.1 DONE!\n");

	req_table.pid = NIT_PID;
	req_table.table_id = 0x40;
	req_table.attr = 0;	
	ts_param.ts_id = g_service_info.transport_stream_id;
	ts_param.proc = change_transponder;	
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_nit_bat_2,
								(void*)(&ts_param));
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 2 error!\n");
		return FALSE;
	}			
	OTA_PRINTF("OTA : step 2.2 DONE!\n");

/* step 3 : get linkage_desc 0x09 */
	step = CHECK_STEP3;
	
	req_table.pid = BAT_PID;
	req_table.table_id = 0x4A;
	req_table.specific_id = 0xFF00; //SSUS
	req_table.attr = DVB_SI_ATTR_SPECIFIC_ID;
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_nit_bat,
								(void*)step);
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 3 error!\n");
		return FALSE;
	}	
	OTA_PRINTF("OTA : step 3.1 DONE!\n");

	
	req_table.pid = NIT_PID;
	req_table.table_id = 0x40;
	req_table.attr = 0;		
	ts_param.ts_id = g_service_info.transport_stream_id;
	ts_param.proc = change_transponder;
		
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_nit_bat_2,
								(void*)(&ts_param));
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 3 error!\n");
		return FALSE;
	}		
	
	OTA_PRINTF("OTA : step 3.2 DONE!\n");

#endif
/* step 4: parse pat section */

	req_table.pid = PAT_PID;
	req_table.table_id = 0x00;
	req_table.attr = 0;	
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_pat,
								(void*)(&g_service_info));
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 4 error!\n");
		return FALSE;
	}	
	OTA_PRINTF("OTA : step 4 parse_pat DONE!\n");
	
/* step 5: parse pmt section */	

	req_table.pid = g_service_info.pmt_pid;
	req_table.table_id = 0x02;
	req_table.specific_id = g_service_info.service_id; 
	req_table.attr = DVB_SI_ATTR_SPECIFIC_ID;
       ret = si_sections_parsing_start((UINT8 *)g_ota_section_buf,
								g_ota_section_buf_len,
								&req_table,
								parse_pmt,
								(void*)(&g_service_info));
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : check_service step 5 error!\n");
		return FALSE;
	}	
	OTA_PRINTF("OTA : step 5 parse_pmt DONE!\n");
	

	*pid = g_service_info.ota_pid;
	return TRUE;	
}

BOOL ota_cmd_get_download_info(UINT16 pid,struct dl_info *info)
{
	UINT32 i,j;
	INT32 ret ;
	struct section_param sec_param;	

	OTA_PRINTF("Get download_info...\n");

	OTA_PRINTF("g_ota_ram1_addr = 0x%8x\n",g_ota_ram1_addr);


/* step 1 : DSI  */

	sec_param.section_type = 0x00;
	
       ret = si_private_sec_parsing_start(0,
	   							pid,
								parse_dsmcc_sec,
								(void*)(&sec_param));	
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : No  ota service exist!\n");
		return FALSE;
	}	

/* step 2 : DII  */

	sec_param.section_type = 0x01;	

       ret = si_private_sec_parsing_start(1,
								pid,
								parse_dsmcc_sec,
								(void*)(&sec_param));
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : No  ota service exist!\n");
		return FALSE;
	}	


	g_ota_size =  g_dl_info.sw_size;
	
	MEMCPY(info, &g_dl_info,sizeof(struct dl_info));

	OTA_PRINTF("Get download inof Done!\n");
	return TRUE;
	
}
BOOL ota_cmd_start_download(UINT16 pid,t_progress_disp progress_disp)
{
	UINT32 i,j;
	INT32 ret;

	UINT8* block_addr;
	UINT32 check_size,check_crc,offset,code_size;
	UINT32 chunk_id = 0;

	if(g_ota_size>g_ota_ram1_len)
	{
		OTA_PRINTF("ERROR: download_buf exceed!\n");
		return FALSE;			
	}
	
/* step 1: process_download */		

OTA_PRINTF("Start Download...\n");

	progress_disp(0);	

	download_progress_disp = progress_disp;

	received_section_num = 0;
	total_block_num = 0;
	for(i=0;i<g_dc_module_num;i++)
		total_block_num+=g_dc_module[i].block_num;
	
       ret = si_private_sec_parsing_start(2,pid,NULL,NULL);
	if(ret != OTA_SUCCESS)
	{
		OTA_PRINTF("ERROR : No  ota service exist!\n");
		return FALSE;
	}	

	progress_disp(100);

#if defined(_S3281_) && defined(_USE_32M_MEM_) 
	nim_close((struct nim_device *)dev_get_by_id(HLD_DEV_TYPE_NIM, 0));
	dmx_stop((struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 0));
	dmx_stop((struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 1));
#endif	
#if defined(_M3383_SABBAT_)
	dmx_stop((struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 0));
	dmx_stop((struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 1));
#endif
	
/* step 2: check crc */		
#ifndef BINCODE_COMPRESSED	

	OTA_PRINTF("Check CRC...\n");

	MG_Setup_CRC_Table();
	offset = 0;
	block_addr = g_ota_ram1_addr;
	code_size = g_ota_size;
	OTA_PRINTF("block_addr = 0x%8x \n",block_addr);
	OTA_PRINTF("code_size = 0x%8x \n",code_size);	
	do{
		block_addr += offset;
		check_size = (block_addr[4]<<24)
					+(block_addr[5]<<16)
					+(block_addr[6]<<8)
					+block_addr[7];

		offset = 		(block_addr[8]<<24)
					+(block_addr[9]<<16)
					+(block_addr[10]<<8)
					+block_addr[11];

		if(offset > code_size)
		{
			OTA_PRINTF("ERROR : size NOT enough !\n");
			return FALSE;//ASSERT(0);//return FALSE;
		}			
		code_size -= offset;
		
		
		check_crc = (block_addr[12]<<24)
					+(block_addr[13]<<16)
					+(block_addr[14]<<8)
					+block_addr[15];
		OTA_PRINTF("crc = 0x%8x \n",check_crc);
		if ((check_crc != NCRC_VALUE) && (check_crc != CAS9_NCRC_VALUE))
		{
			if(check_crc != (UINT32)MG_Table_Driven_CRC(0xFFFFFFFF, block_addr + 0x10, check_size))
			{
				OTA_PRINTF("ERROR : CRC error !\n");
				return FALSE;//ASSERT(0);//return FALSE;
			}	
		}
	}while(offset!=0&&code_size>0);
	
#else

	OTA_PRINTF("Unzip code...\n");
#ifndef OTA_STATIC_SWAP_MEM	
	if((g_ota_swap_addr = MALLOC(256*1024)) == NULL)
	{
		OTA_PRINTF("ERROR: malloc swap buffer failed!\n");
		return FALSE;
	}
#endif
	if(un7zip(g_ota_ram1_addr,g_ota_ram2_addr,g_ota_swap_addr) != 0)
	{
#ifndef OTA_STATIC_SWAP_MEM	
		FREE(g_ota_swap_addr);
#endif
		OTA_PRINTF("ERROR: un7zip failed!\n");
		return FALSE;		
	}
	g_ota_size_2 = *((UINT32*)g_ota_swap_addr);
#ifndef OTA_STATIC_SWAP_MEM	
	FREE(g_ota_swap_addr);
#endif
	if((UINT32)g_ota_size_2>g_ota_ram2_len)
	{
		OTA_PRINTF("ERROR: unzip_buf exceed!\n");
		return FALSE;			
	}

	OTA_PRINTF("Check CRC...\n");

	MG_Setup_CRC_Table();
	offset = 0;
	block_addr = g_ota_ram2_addr;
	code_size = g_ota_size_2;
	UINT32 total_code_size  = code_size;
	OTA_PRINTF("block_addr = 0x%8x \n",block_addr);
	OTA_PRINTF("code_size = 0x%8x \n",code_size);	
	do{
		block_addr += offset;
		
		chunk_id = (block_addr[0]<<24)
					+(block_addr[1]<<16)
					+(block_addr[2]<<8)
					+block_addr[3];
		
		check_size = (block_addr[4]<<24)
					+(block_addr[5]<<16)
					+(block_addr[6]<<8)
					+block_addr[7];

		offset = 		(block_addr[8]<<24)
					+(block_addr[9]<<16)
					+(block_addr[10]<<8)
					+block_addr[11];

		if(offset > code_size)
		{
			OTA_PRINTF("ERROR : size NOT enough !\n");
			return FALSE;//ASSERT(0);//return FALSE;
		}			
		code_size -= offset;
		
		
		check_crc = (block_addr[12]<<24)
					+(block_addr[13]<<16)
					+(block_addr[14]<<8)
					+block_addr[15];
		OTA_PRINTF("crc = 0x%8x \n",check_crc);
		if(0x23010010 == chunk_id )// 3281 bootloader crc = 0 ,crc be used for other purpose.
		{
			continue;
		}		
			
		if ((check_crc != NCRC_VALUE) && (check_crc != CAS9_NCRC_VALUE))
		{
			if(check_crc != (UINT32)MG_Table_Driven_CRC(0xFFFFFFFF, block_addr + 0x10, check_size))
			{
				OTA_PRINTF("ERROR : CRC error !\n");
				return FALSE;//ASSERT(0);//return FALSE;
			}	
		}
	}while(offset!=0&&code_size>0);	
#endif
	
	OTA_PRINTF("Download Finished !\n");
	return TRUE;

	
}

BOOL mem_cmp(UINT8* src,UINT8* dst,UINT32 size)
{
	UINT32 i;
	for(i=0;i<size;i++)
		if(*src++ != *dst++) return FALSE;
	return TRUE;
}

//new code, it use relative address & sto interface to read the flash
BOOL ota_cmd_start_burnflash(t_progress_disp progress_disp)
{
	UINT32 offset;
	UINT32 code_size, write_size;
	UINT8* m_block_addr;
	UINT8* m_f_block_addr;	//read flash data to sdram
	UINT32 f_block_addr;	//relative address
	
	struct sto_device *f_dev;
	UINT32 param;

#ifdef OTA_STATIC_SWAP_MEM
	m_f_block_addr = g_ota_swap_addr;
#else
	//malloc a sector
	if ((m_f_block_addr = (UINT8*)MALLOC(SECTOR_SIZE)) == NULL)
	{
		OTA_PRINTF("ERROR: malloc failed!\n");
		return FALSE;
	}
#endif

	/* Init FLASH device */
	if ((f_dev = (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0)) == NULL)
	{
		OTA_PRINTF("ERROR: Not found Flash device!\n");
#ifndef OTA_STATIC_SWAP_MEM
		FREE(m_f_block_addr);
#endif
		return FALSE;
	}
	if (sto_open(f_dev) != SUCCESS)
	{
		OTA_PRINTF("ERROR: sto_open failed!\n");
#ifndef OTA_STATIC_SWAP_MEM
		FREE(m_f_block_addr);
#endif
		return FALSE;
	}
#ifdef HDCP_IN_FLASH
	{
		UINT8 	*hdcp_internal_keys;
		CHUNK_HEADER hdcp_chuck_hdr;
		UINT32 hdcp_chuck_id = HDCPKEY_CHUNK_ID;			

		if(sto_get_chunk_header(hdcp_chuck_id,&hdcp_chuck_hdr)!=0)
		{
			// read back the hdcp key from flash
			hdcp_internal_keys = (UINT8 *)MALLOC(sizeof(UINT8)*hdcp_chuck_hdr.offset);	
			sto_get_data( (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0), hdcp_internal_keys,
								(UINT32)sto_chunk_goto(&hdcp_chuck_id,0xFFFFFFFF,1), hdcp_chuck_hdr.offset);		
			// restore back the hdcp key to all code image					
			MEMCPY(g_ota_ram2_addr +(UINT32)sto_chunk_goto(&hdcp_chuck_id,0xFFFFFFFF,1) ,hdcp_internal_keys,hdcp_chuck_hdr.offset);		
			FREE(hdcp_internal_keys);
		}
	}
#endif

#ifdef CI_PLUS_SUPPORT
	{
        UINT8   *ci_plus_internal_keys;
        CHUNK_HEADER ci_plus_chuck_hdr;
        UINT32 ci_plus_chuck_id = 0x09F60101;

        if(sto_get_chunk_header(ci_plus_chuck_id,&ci_plus_chuck_hdr)!=0)
        {
            // read back the hdcp key from flash
            ci_plus_internal_keys = (UINT8 *)MALLOC(sizeof(UINT8)*ci_plus_chuck_hdr.offset);    
            sto_get_data( (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0), ci_plus_internal_keys,
                    (UINT32)sto_chunk_goto(&ci_plus_chuck_id,0xFFFFFFFF,1), ci_plus_chuck_hdr.offset);      
            // restore back the hdcp key to all code image                  
            MEMCPY(g_ota_ram2_addr +(UINT32)sto_chunk_goto(&ci_plus_chuck_id,0xFFFFFFFF,1),ci_plus_internal_keys,ci_plus_chuck_hdr.offset);      
            FREE(ci_plus_internal_keys);
        } 
    }
#endif

#ifdef BINCODE_COMPRESSED
	m_block_addr = g_ota_ram2_addr;
	f_block_addr = 0; //relative address

	sto_get_data(f_dev, m_f_block_addr, f_block_addr, 12);

	offset = 	(m_f_block_addr[8]<<24)
				+(m_f_block_addr[9]<<16)
				+(m_f_block_addr[10]<<8)
				+m_f_block_addr[11];		
	OTA_PRINTF("offset0 %d\n",offset);
	f_block_addr += offset; //skip bootloader of flash address

	offset = 	(m_block_addr[8]<<24)
				+(m_block_addr[9]<<16)
				+(m_block_addr[10]<<8)
				+m_block_addr[11];		
	OTA_PRINTF("offset1 %d\n",offset);
	m_block_addr += offset; //skip bootloader of sdram address
#ifdef HDCP_IN_FLASH
	g_ota_size_2 -= offset;

	sto_get_data(f_dev, m_f_block_addr, f_block_addr, 12);

	
	offset = 	(m_f_block_addr[8]<<24)
				+(m_f_block_addr[9]<<16)
				+(m_f_block_addr[10]<<8)
				+m_f_block_addr[11];		
	OTA_PRINTF("offset2 %x\n",offset);
	f_block_addr += offset; //skip hdcp key  of flash address

	offset = 	(m_block_addr[8]<<24)
				+(m_block_addr[9]<<16)
				+(m_block_addr[10]<<8)
				+m_block_addr[11];		
	OTA_PRINTF("offset3 %x\n",offset);
	m_block_addr += offset; //skip hdcp key of sdram address
#endif

	g_ota_size_2 -= offset;
	code_size = g_ota_size_2;

#ifdef RECOVERY_CODE_EXIST	

	sto_get_data(f_dev, m_f_block_addr, f_block_addr, 12);

	offset = 	(m_f_block_addr[8]<<24)
				+(m_f_block_addr[9]<<16)
				+(m_f_block_addr[10]<<8)
				+m_f_block_addr[11];		
	OTA_PRINTF("offset2 %d\n",offset);
	f_block_addr += offset;	//skip secondloader of flash address

	offset = 	(m_block_addr[8]<<24)
				+(m_block_addr[9]<<16)
				+(m_block_addr[10]<<8)
				+m_block_addr[11];		
	OTA_PRINTF("offset3 %d\n",offset);
	m_block_addr += offset;	//skip secondloader of sdram address	
	g_ota_size_2 -= offset;
	code_size = g_ota_size_2;	
#endif

#else
	g_ota_size_2 = g_ota_size;
	code_size = g_ota_size;
	m_block_addr = g_ota_ram1_addr;
	f_block_addr = 0;	////relative address not abs address

	if (sto_lseek(f_dev, (INT32)f_block_addr, STO_LSEEK_SET) != (INT32)f_block_addr)
	{
		OTA_PRINTF("ERROR: sto_lseek failed!\n");
#ifndef OTA_STATIC_SWAP_MEM
		FREE(m_f_block_addr);
#endif
		return FALSE;
	}
	if (sto_read(f_dev, m_f_block_addr, SECTOR_SIZE) != SECTOR_SIZE)
	{
		OTA_PRINTF("ERROR: sto_read failed!\n");
		FREE(m_f_block_addr);
		return FALSE;
	}

	offset = 	(m_f_block_addr[8]<<24)
				+(m_f_block_addr[9]<<16)
				+(m_f_block_addr[10]<<8)
				+m_f_block_addr[11];		
	f_block_addr += offset; //skip bootloader of flash address
	code_size -= offset;
	g_ota_size_2 -= offset;
	m_block_addr += offset; //skip bootloader of sdram address
#endif
#ifdef OTA_POWEROFF_SAFE
	UINT32 f_backup_addr;
	UINT8 *userdb_addr = 0;
	UINT32 chid = 0x04FB0100;
	UINT32 ota_restore_size,ota_m_size,start_flag;
	UINT8 *ota_restore_addr,*ota_m_addr;
	UINT8 b_end_mark[16] = {0x65,0x72,0x6F,0x74,0x73,0x65,0x72,0x5F,0x67,0x6F,0x72,0x70,0x5F,0x61,0x74,0x6F};/* erotser_gorp_ato*/

	f_backup_addr = SYS_FLASH_BASE_ADDR + f_dev->totol_size - g_ota_size - 20;
	//align to 64k
	f_backup_addr = f_backup_addr - f_backup_addr%(64*1024);
	
	param = f_backup_addr - SYS_FLASH_BASE_ADDR;
	if((g_ota_size+20) < (f_dev->totol_size - param))
	{
		/* find position of userdb */
		chunk_init((UINT32)g_ota_ram2_addr,SYS_FLASH_SIZE);
		userdb_addr = (UINT8*)chunk_goto(&chid, 0xFFFFFFFF, 1) ;
		g_ota_size_2 = (userdb_addr-g_ota_ram2_addr);
		g_ota_size_2 += 0x80; /* user db chunk header */
		g_ota_size_2 -= offset;
		code_size = g_ota_size_2;
		
		ota_restore_addr = (UINT8 *)f_backup_addr - SYS_FLASH_BASE_ADDR;
		progress_disp(OTA_START_BACKUP_FLAG);
		/* erase flash space for backup */
		//20080918, sync with dvb-c, for flash size >= 4M
		UINT32 tmp_param[2];
		tmp_param[0] = param;
		/* length in K bytes*/
		tmp_param[1] = (f_dev->totol_size-(INT32)ota_restore_addr) >> 10;
		param = (UINT32)tmp_param;

		progress_disp(3);

		if(sto_io_control(f_dev, STO_DRIVER_SECTOR_ERASE_EXT, param) != SUCCESS)
		{
			OTA_PRINTF("ERROR: ota clean-up restore data sectors  failed!\n");
			return FALSE;
		}
		/* write start backup flag */
		progress_disp(15);
		if (sto_lseek(f_dev,(INT32)ota_restore_addr+16,STO_LSEEK_SET) != (INT32)ota_restore_addr+16)
		{
			OTA_PRINTF("ERROR: ota restore sto_lseek failed!\n");
			return FALSE;
		}
		start_flag = BACKUP_START_FLAG;
		if(sto_write(f_dev,(UINT8 *) &start_flag, 4)!=4)
		{
			OTA_PRINTF("ERROR:ota restore write start flag  failed!\n");
			return FALSE;
		}
		progress_disp(20);
		/* write ota data to bfd20000*/
		ota_restore_size = g_ota_size;
		ota_restore_addr += 20;
		ota_m_addr = g_ota_ram1_addr;
		while(ota_restore_size)
		{
			write_size = (ota_restore_size < SECTOR_SIZE) ? ota_restore_size : SECTOR_SIZE;	
			if (sto_lseek(f_dev,(INT32)ota_restore_addr,STO_LSEEK_SET) != (INT32)ota_restore_addr)
			{
				OTA_PRINTF("ERROR: ota sto_lseek failed!\n");
				return FALSE;
			}	
			if(sto_write(f_dev, ota_m_addr, write_size)!=(INT32)write_size)
			{
				OTA_PRINTF("ERROR:ota write restore data failed!\n");
				return FALSE;
			}		
			ota_restore_addr +=SECTOR_SIZE;			
			ota_m_addr +=write_size;			
			ota_restore_size -= write_size;
			progress_disp((g_ota_size-ota_restore_size)*80/g_ota_size +20);
		}
		/* write restore data done flag */
		ota_restore_addr = (UINT8*)f_backup_addr - SYS_FLASH_BASE_ADDR;
		if (sto_lseek(f_dev,(INT32)ota_restore_addr,STO_LSEEK_SET) != (INT32)ota_restore_addr)
		{
			OTA_PRINTF("ERROR: ota sto_lseek failed!\n");
			return FALSE;
		}	
		if(sto_write(f_dev, (UINT8 *)b_end_mark, 16)!=16)
		{
			OTA_PRINTF("ERROR:ota write restore done flag failed!\n");
			return FALSE;
		}
		progress_disp(100);
		progress_disp(OTA_START_END_FLAG);
		
	}
#endif

	while(code_size)
	{
	    write_size = (code_size < SECTOR_SIZE) ? code_size : SECTOR_SIZE;

		sto_get_data(f_dev, m_f_block_addr, f_block_addr, write_size);

		if(mem_cmp(m_f_block_addr, m_block_addr, write_size)==FALSE)
		{
			//20080918, sync with dvb-c, for flash size >= 4M
			UINT32 tmp_param[2];
			tmp_param[0] = f_block_addr;
			/* length in K bytes*/
			tmp_param[1] = SECTOR_SIZE >> 10;
			param = (UINT32)tmp_param;

			if(sto_io_control(f_dev, STO_DRIVER_SECTOR_ERASE_EXT, param) != SUCCESS)
			{
				OTA_PRINTF("ERROR: erase flash memory failed!\n");
#ifndef OTA_STATIC_SWAP_MEM
				FREE(m_f_block_addr);
#endif
				return FALSE;
			}		
#if 1
			if (sto_lseek(f_dev,(INT32)f_block_addr,STO_LSEEK_SET) != (INT32)f_block_addr)
			{
				OTA_PRINTF("ERROR: sto_lseek failed!\n");
#ifndef OTA_STATIC_SWAP_MEM
				FREE(m_f_block_addr);
#endif
				return FALSE;
			}	
			if(sto_write(f_dev, m_block_addr, write_size)!=(INT32)write_size)
			{
				OTA_PRINTF("ERROR: sto_write failed!\n");
#ifndef OTA_STATIC_SWAP_MEM
				FREE(m_f_block_addr);
#endif
				return FALSE;
			}		
#else
			sto_put_data(f_dev, f_block_addr, m_f_block_addr, SECTOR_SIZE);
#endif
		}
		f_block_addr +=SECTOR_SIZE;			
		m_block_addr +=write_size;			
		code_size -= write_size;
		progress_disp((g_ota_size_2-code_size)*100/g_ota_size_2);
	}

	OTA_PRINTF("Write flash done!\n");
#ifndef OTA_STATIC_SWAP_MEM
	FREE(m_f_block_addr);
#endif
	return TRUE;
		
}

INT32 BackupDatabase(UINT32 backup_db_addr ,UINT32 user_db_len ,UINT32 user_db_addr_offset )
{
	struct sto_device *sto_dev = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
    INT32 er;

	if(sto_lseek(sto_dev, (INT32)user_db_addr_offset, STO_LSEEK_SET) !=  (INT32)user_db_addr_offset)
        return ERR_FAILED;
	if(sto_read(sto_dev, (UINT8 *)backup_db_addr, (INT32)user_db_len) != (INT32)user_db_len)
        return ERR_FAILED;
    return SUCCESS;
}

INT32 BurnBlock(UINT8 *pBuffer, UINT32 Pos, UINT8 NumSectors,t_burn_progress_disp burn_progress, UINT32* update_sector_index,UINT32 total_sectors)
{
	struct sto_device *sto_dev =  (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
    UINT32 param;
    INT32 offset, er = SUCCESS;
    UINT8 i;

    for(i=0; i<NumSectors; i++)
    {
        offset = (Pos + i) * SECTOR_SIZE;
        //param = ((UINT32)offset) << 10; // upper 22 bits is offset based on SYS_FLASH_BASE_ADDR
        //param += SECTOR_SIZE >> 10;   // lower 10 bits is length in K bytes
       // OTA_PRINTF("%s: erase sector %d\n", __FUNCTION__, Pos+i);
       // er = sto_io_control(sto_dev, STO_DRIVER_SECTOR_ERASE, param);
      	 UINT32 tmp_param[2];
				tmp_param[0] =((UINT32)offset) ;
				tmp_param[1] =SECTOR_SIZE>>10  ;
				param= (UINT32)tmp_param;
        OTA_PRINTF("%s: erase sector %d\n", __FUNCTION__, Pos+i);
				 er = sto_io_control(sto_dev, STO_DRIVER_SECTOR_ERASE_EXT, param);//Summic add for check the >=4M Flash
        if(er != SUCCESS)
        {
            OTA_PRINTF("%s: erase sector %d failed\n", __FUNCTION__, i);
            break;
        }

        if(pBuffer)
        {
            OTA_PRINTF("%s: seek sector %d, offset = %xh\n", __FUNCTION__, Pos+i,offset);
            if(sto_lseek(sto_dev, offset, STO_LSEEK_SET) != offset)
            {
                OTA_PRINTF("%s: seek sector %d failed\n", __FUNCTION__, i);
                er = ERR_FAILED;
                break;
            }

            OTA_PRINTF("%s: write sector %d, src = %xh\n", __FUNCTION__, Pos+i,&pBuffer[SECTOR_SIZE * i]);
            if(sto_write(sto_dev, &pBuffer[SECTOR_SIZE * i], SECTOR_SIZE) != SECTOR_SIZE)
            {
                OTA_PRINTF("%s: write sector %d failed\n", __FUNCTION__, i);
                er = ERR_FAILED;
                break;
            }
        }
	 *update_sector_index=(*update_sector_index+1);
        burn_progress((UINT8)(((*update_sector_index)*100)/total_sectors));
    }
    return er;
}

BOOL ota_cmd_service_stopped()
{
	struct dmx_device * dmx_dev;
	if((dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 0)) == NULL)
	{
		OTA_PRINTF("ERROR : get dmx dev failure !");
		return OTA_FAILURE;
	}		
	dmx_io_control(dmx_dev, CLEAR_STOP_GET_SECTION, (UINT32)NULL);
}

#ifndef OTA_STATIC_SWAP_MEM
void ota_mem_config(UINT32 compressed,UINT32 compressed_len,UINT32 uncompressed,UINT32 uncompressed_len)
#else
void ota_mem_config(UINT32 compressed,UINT32 compressed_len,UINT32 uncompressed,UINT32 uncompressed_len,UINT32 swap_addr,UINT32 swap_len)
#endif
{
	g_ota_ram1_addr = (UINT8*)compressed;
	g_ota_ram1_len = compressed_len;
	g_ota_ram2_addr  = (UINT8*)uncompressed;	
	g_ota_ram2_len = uncompressed_len;
#ifdef OTA_STATIC_SWAP_MEM	
	g_ota_swap_addr= (UINT8*)swap_addr;
	ASSERT(swap_len> 128*1024);
#endif	
#ifndef BINCODE_COMPRESSED	
	g_ota_ram1_addr = (UINT8*)uncompressed;
	g_ota_ram1_len = uncompressed_len;
#endif
}
BOOL ota_check_service(UINT32 lnb_freq,UINT16* pid)
{
	g_lnb_frequency = lnb_freq;
	
#ifdef OTA_CONTROL_FLOW_ENHANCE	
	struct ota_cmd this_cmd;
	UINT32 flgptn_after;

	this_cmd.cmd_type = OTA_CHECK_SERVICE;
	this_cmd.para16 = 0;
	this_cmd.para32 = (UINT32)pid;
	return (E_OK == ota_send_cmd(&this_cmd,OSAL_WAIT_FOREVER_TIME));
#else
	return ota_cmd_check_service(pid);
#endif
}
BOOL ota_get_download_info(UINT16 pid,struct dl_info *info)
{
#ifdef OTA_CONTROL_FLOW_ENHANCE
	struct ota_cmd this_cmd;
	UINT32 flgptn_after;

	this_cmd.cmd_type = OTA_GET_DOWNLOADINFO;
	this_cmd.para16 = pid;
	this_cmd.para32 = (UINT32)info;

	return (E_OK == ota_send_cmd(&this_cmd,OSAL_WAIT_FOREVER_TIME));
#else
	return ota_cmd_get_download_info(pid,info);
#endif
}
BOOL ota_start_download(UINT16 pid,t_progress_disp progress_disp)
{
#ifdef OTA_CONTROL_FLOW_ENHANCE	
	struct ota_cmd this_cmd;
	UINT32 flgptn_after;

	this_cmd.cmd_type = OTA_START_DOWNLOAD;
	this_cmd.para16 = pid;
	this_cmd.para32 = (UINT32)progress_disp;

	return (E_OK == ota_send_cmd(&this_cmd,OSAL_WAIT_FOREVER_TIME));
#else
	return ota_cmd_start_download(pid,progress_disp);
#endif
}
BOOL ota_start_burnflash(t_progress_disp progress_disp)
{
#ifdef OTA_CONTROL_FLOW_ENHANCE	
	struct ota_cmd this_cmd;
	UINT32 flgptn_after;

	this_cmd.cmd_type = OTA_START_BURNFLASH;
	this_cmd.para16 = 0;
	this_cmd.para32 = (UINT32)progress_disp;

	return (E_OK == ota_send_cmd(&this_cmd,100));
#else
	return ota_cmd_start_burnflash(progress_disp);
#endif
}
BOOL ota_stop_service(void)
{
#ifdef OTA_CONTROL_FLOW_ENHANCE	
	struct ota_cmd this_cmd;
	UINT flgptn = 0;
	
	struct dmx_device * dmx_dev;
	
#if (SYS_PROJECT_FE == PROJECT_FE_DVBT) && (SYS_CHIP_MODULE == ALI_M3327C) && (SYS_SDRAM_SIZE == 2)
    if(g_ota_tsk_id != OSAL_INVALID_ID)
    {
#endif
	if((dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 0)) == NULL)
	{
		OTA_PRINTF("ERROR : get dmx dev failure !");
		return FALSE;   //OTA_FAILURE;
	}	
	dmx_io_control(dmx_dev, IO_STOP_GET_SECTION, (UINT32)NULL);

	this_cmd.cmd_type = OTA_STOP_SERVICE;
	this_cmd.para16 = 0;
	this_cmd.para32 = 0;

	ota_send_cmd(&this_cmd,OSAL_WAIT_FOREVER_TIME);

#if (SYS_PROJECT_FE == PROJECT_FE_DVBT) && (SYS_CHIP_MODULE == ALI_M3327C) && (SYS_SDRAM_SIZE == 2)
    osal_flag_wait(&flgptn, g_ota_flg_id, (PROC_SUCCESS | PROC_FAILURE | PROC_STOPPED), OSAL_TWF_ORW, OSAL_WAIT_FOREVER_TIME);
    osal_flag_delete(g_ota_flg_id);
    osal_msgqueue_delete(g_ota_mbf_id);
    g_ota_mbf_id = g_ota_flg_id = OSAL_INVALID_ID;
        g_ota_tsk_id = OSAL_INVALID_ID;
    }
#endif
#endif
    return TRUE;
}
BOOL ota_reboot(void)
{
	pan_close(dev_get_by_id(HLD_DEV_TYPE_PAN, 0));
#ifdef WATCH_DOG_SUPPORT
    dog_stop(0);
#endif     
	sys_watchdog_reboot();	
}	

#ifdef OTA_CONTROL_FLOW_ENHANCE
INT32 ota_send_cmd(struct ota_cmd* cmd,UINT32 tmout)
{
    return osal_msgqueue_send(g_ota_mbf_id, cmd, sizeof(struct ota_cmd),tmout);
}

BOOL ota_cmd_implement(UINT16 ota_cmd, UINT16 para16, UINT32 para32)
{
	BOOL ret_bool = FALSE;
	switch(ota_cmd)
	{
	case OTA_CHECK_SERVICE:
		ret_bool = ota_cmd_check_service((UINT16*)para32);
		osal_flag_set(g_ota_flg_id,(ret_bool == TRUE)?PROC_SUCCESS:PROC_FAILURE);
		break;		
	case OTA_GET_DOWNLOADINFO:
		ret_bool = ota_cmd_get_download_info(para16,(struct dl_info *)para32);
		osal_flag_set(g_ota_flg_id,(ret_bool == TRUE)?PROC_SUCCESS:PROC_FAILURE);
		break;		
	case OTA_START_DOWNLOAD:
		ret_bool = ota_cmd_start_download(para16,(t_progress_disp)para32);
		osal_flag_set(g_ota_flg_id,(ret_bool == TRUE)?PROC_SUCCESS:PROC_FAILURE);
		break;
	case OTA_START_BURNFLASH:
		ret_bool = ota_cmd_start_burnflash((t_progress_disp)para32);
        	osal_flag_set(g_ota_flg_id,(ret_bool == TRUE)?PROC_SUCCESS:PROC_FAILURE);
		break;
	case OTA_STOP_SERVICE:
		ret_bool = ota_cmd_service_stopped();
		osal_flag_set(g_ota_flg_id,PROC_STOPPED);
		break;		
	default :		
		break;

	}
	
	return ret_bool;
}

void ota_cmd_implement_wrapped(struct ota_cmd * ota_cmd)
{
	ota_cmd_implement(ota_cmd->cmd_type,ota_cmd->para16,ota_cmd->para32);
}

void ota_task(void)
{
	OSAL_ER ret_val;
	UINT32 msg_size;	
	struct ota_cmd msg;	
	while(1)
	{
		ret_val = osal_msgqueue_receive((VP)&msg, &msg_size, g_ota_mbf_id,OSAL_WAIT_FOREVER_TIME);
		if ((ret_val != E_OK) || (msg_size != sizeof(struct ota_cmd)))
		{
			continue;
		}
		ota_cmd_implement_wrapped(&msg);
#if (SYS_PROJECT_FE == PROJECT_FE_DVBT) && (SYS_CHIP_MODULE == ALI_M3327C) && (SYS_SDRAM_SIZE == 2)
        if(OTA_STOP_SERVICE == msg.cmd_type)
            break;
#endif
	}
}
#endif
BOOL ota_init(void)
{
#ifdef OTA_CONTROL_FLOW_ENHANCE
	T_CMBF t_cmbf;
	T_CTSK t_ctsk;

	t_cmbf.bufsz =  sizeof(struct ota_cmd) * 20;
	t_cmbf.maxmsz = sizeof(struct ota_cmd);
	g_ota_mbf_id = osal_msgqueue_create(&t_cmbf);

	if (g_ota_mbf_id == OSAL_INVALID_ID)
	{
		OTA_PRINTF("OTA: cre_mbf ota_msgbuf_id failed in %s\n",__FUNCTION__);
		return FALSE;
	}

	t_ctsk.task = (FP)ota_task;
#if (SYS_PROJECT_FE == PROJECT_FE_DVBT) && (SYS_CHIP_MODULE == ALI_M3327C) && (SYS_SDRAM_SIZE == 2)
	t_ctsk.stksz = 0x400;
#else
	t_ctsk.stksz = 0x1000;
#endif
	t_ctsk.quantum = 10;
	t_ctsk.itskpri = OSAL_PRI_NORMAL;
	t_ctsk.name[0] = 'O';
	t_ctsk.name[1] = 'T';
	t_ctsk.name[2] = 'A';

	g_ota_tsk_id = osal_task_create(&t_ctsk);	
	if (g_ota_tsk_id == OSAL_INVALID_ID)
	{
	    OTA_PRINTF("OTA: cre_tsk g_ota_tsk_id failed in %s\n",__FUNCTION__);
	    return FALSE;
	}
	
	g_ota_flg_id=osal_flag_create(0x00000000);
	if(OSAL_INVALID_ID==g_ota_flg_id)
	{
	    OTA_PRINTF("OTA: cre_flg g_ota_flg_id failed in %s\n",__FUNCTION__);
	    return FALSE;  
	}	
#endif	

    return TRUE;
}
#endif

#ifdef SUPPORT_FIRMWARE_CONFIG
void ota_config(UINT32 oui, UINT16 model, UINT16 hw_version, UINT16 sw_model)
{
    g_oui = oui;
    g_model = model;
    g_hw_version = hw_version;
    g_sw_model = sw_model;
}
#endif
#ifdef AUTO_OTA_SAME_VERSION_CHECK
void ota_config(UINT32 oui, UINT16 model, UINT16 hw_version, UINT16 sw_model)
{
    g_oui = oui;
    g_model = model;
    g_hw_version = hw_version;
    g_sw_model = sw_model;
    
    set_ota_software_version_arbitration(DO_NOT_CARE_SOFTWARE_VERSION);
}

void ota_config_ex(UINT32 oui, UINT16 model, UINT16 hw_version, UINT16 sw_model, UINT16 sw_version, OTA_SOFTWARE_VERSION_ARBITRATION software_version_arbitration)
{
    g_oui = oui;
    g_model = model;
    g_hw_version = hw_version;
    g_sw_model = sw_model;
    
    g_sw_version = sw_version;
    set_ota_software_version_arbitration(software_version_arbitration);
}
#endif
